package com.chapter20.demo2;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


/**
 * Executors工具类
 *  Executors工具类定义了 Executors.newCachedThreadPool、newFixedThreadPool、newSingleThreadExecutor方法来得到一个ExecutorService对象：
 *      newCachedThreadPool创建一个可自动增长容量的线程池。在执行任务时，如果有可用的线程，则直接使用它来执行任务，如果没有可用
 *      的线程，则创建一个新的线程加入到线程池中。空闲线程只保留60秒，超过时间的空闲线程将被终止并从线程池中删除。
 *  ExecutorService接口扩展自Executor，定义了执行任务和终止任务的方法，该接口中的主要方法：
 *      ●Future<?> submit(Runnable task)
 *      提交Runnable任务以供执行，返回表示该任务的Future对象。
 *      ● <T> Future<T> submit(Runnable task, T result)
 *      提交Runnable任务以供执行，返回表示该任务的Future对象。Future的get方法将在成功完成后返回result。
 *      ● <T> Future<T> submit(Callable<T> task)
 *      提交Callable任务以供执行，返回表示该任务的Future对象。Future的get方法将在成功完成后返回任务的结果。
 *      ● void shutdown()执行已提交的任务，但不接受新任务。。。。
 *
 * 使用JUC新的API来执行任务，通常遵循以下步骤：
 * （1）调用Executors的newXxx方法创建一个线程池，即得到一个ExecutorService对象。
 * （2）调用ExecutorService的submit方法提交Runnable任务或者Callable任务，可提交多个。
 * （3）保存好submit方法调用返回的Future对象，以便得到结果或取消任务。
 * （4）当不需要再提交新的任务时，调用ExecutorService的shutdown方法。
 */
public class FactorialWithExecutor {
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        //保存好submit方法调用返回的Future对象，以便得到结果或取消任务。
        ArrayList<Future<Integer>> results = new ArrayList<>();
        for(int i=0;i<10;i++){
            //ExecutorService的submit方法提交Runnable任务或者Callable任务，可提交多个。
            results.add(exec.submit(new FactorialTask(i)));
        }
        //当不需要再提交新的任务时，调用shutdown方法。阻止新任务的添加，但不影响之前提交的任务
        exec.shutdown();
        for(int i=0;i<10;i++){
        //for(int i=0;results.size();i++){

                //Future的get方法将在成功完成后返回result。
            Future<Integer> result = results.get(i);
            try {
                System.out.println(i+ "的阶乘是：" + result.get());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
